#include <benchmark/benchmark.h>
#include "bench.hpp"
#include <vector>

static void BM_AoS(benchmark::State& state) {
    const std::size_t N = static_cast<std::size_t>(state.range(0));
    const int iters = static_cast<int>(state.range(1));

    // 系数
    const float a = 1.001f, b = 0.999f, c = 1.003f, d = 0.997f;
    const double e = 1.0003, f = 0.5001;

    // 初始化一次，保持原始拷贝用于每次迭代复位
    std::vector<ParticleAoS> aos(N), aos_init(N);
    ParticlesSoA tmp_soa(N); // 仅用于 init 填充
    init_particles(aos, tmp_soa, 42);
    aos_init = aos;

    for (auto _ : state) {
        state.PauseTiming();
        aos = aos_init; // 复位数据，不计入时间
        state.ResumeTiming();

        float cs = bench_aos(aos, iters, a, b, c, d, e, f);
        benchmark::DoNotOptimize(cs);
        benchmark::ClobberMemory();
    }

    state.SetItemsProcessed(state.iterations() * static_cast<long long>(N) * iters);
}

static void BM_SoA(benchmark::State& state) {
    const std::size_t N = static_cast<std::size_t>(state.range(0));
    const int iters = static_cast<int>(state.range(1));

    const float a = 1.001f, b = 0.999f, c = 1.003f, d = 0.997f;
    const double e = 1.0003, f = 0.5001;

    // 初始化一次，保持原始拷贝用于每次迭代复位
    ParticlesSoA soa(N), soa_init(N);
    std::vector<ParticleAoS> tmp_aos(N); // 仅用于 init 填充
    init_particles(tmp_aos, soa, 42);
    soa_init = soa;

    for (auto _ : state) {
        state.PauseTiming();
        soa = soa_init; // 复位数据，不计入时间
        state.ResumeTiming();

        float cs = bench_soa(soa, iters, a, b, c, d, e, f);
        benchmark::DoNotOptimize(cs);
        benchmark::ClobberMemory();
    }

    state.SetItemsProcessed(state.iterations() * static_cast<long long>(N) * iters);
}

BENCHMARK(BM_AoS)->ArgNames({"N", "iters"})->Args({2'000'000, 5});
BENCHMARK(BM_SoA)->ArgNames({"N", "iters"})->Args({2'000'000, 5});

BENCHMARK_MAIN();